package com.imooc.controller;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.google.gson.Gson;
import com.imooc.base.BaseInfoProperties;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.pojo.Users;
import com.imooc.pojo.VO.SaasUserVO;
import com.imooc.service.UsersService;
import com.imooc.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 扫码登录
 */
@RestController
@RequestMapping("saas")
@Slf4j
public class SaasPassportController extends BaseInfoProperties {

    @Autowired
    private JWTUtils jwtUtils;
    @Autowired
    private UsersService usersService;


    /**
     * 企业后台获得二维码token
     */
    @PostMapping("getQRToken")
    public GraceJSONResult getQRToken() {

        // 生成扫码登录的token
        String qrToken = UUID.randomUUID().toString();
        // 把qrToken存入redis，并设置过期时间
        redis.set(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken, qrToken, 5 * 60);
        // 存入redis标记当前qrToken未被读取
        redis.set(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken, "0", 5 * 60);

        return GraceJSONResult.ok(qrToken);
    }

    /**
     * APP端扫码登录
     */
    @PostMapping("scanCode")
    public GraceJSONResult scanCode(String qrToken, HttpServletRequest request) {

        // 判空
        if (StringUtils.isBlank(qrToken))
            return GraceJSONResult.errorCustom(ResponseStatusEnum.FAILED);

        String redisToken = redis.get(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken);

        if (!redisToken.equalsIgnoreCase(qrToken))
            return GraceJSONResult.errorCustom(ResponseStatusEnum.FAILED);

        // 从header中获得用户id和token
        String appUserId = request.getHeader("appUserId");
        String appUserToken = request.getHeader("appUserToken");

        // 判空
        if (StringUtils.isEmpty(appUserId) || StringUtils.isEmpty(appUserToken))
            return GraceJSONResult.errorCustom(ResponseStatusEnum.FAILED);

        // 对JWT校验
        String userJson = jwtUtils.checkJWT(appUserToken.split(JWTUtils.at)[1]);
        if (StringUtils.isBlank(userJson)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.FAILED);
        }

        // 执行后续正常业务
        // 生成预登录令牌
        String preToken = UUID.randomUUID().toString();
        redis.set(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken, preToken, 5 * 60);
        // redis写入标记，当前qrToken需要被读取并且实效覆盖，网页端标记二维码已被扫
        redis.set(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken, "1," + preToken, 5 * 60);

        // 返回给手机端，app下次请求携带preToken
        return GraceJSONResult.ok(preToken);
    }

    /**
     * 企业后台查询二维码是否被读
     * SAAS网页端每隔一段时间（3秒）定时查询qrToken是否被读取，用于页面的展示标记判断
     * 前端处理： 限制用户中页面不操作而频繁发起调用：「页面实效，请刷新后再执行扫码登录！」
     * 注：如果使用websocket或者netty，可以在app扫描之后，在上一个接口，直接通信浏览器（H5）进行页面扫码的状态标记
     */
    @PostMapping("/codeHasBeenRead")
    public GraceJSONResult codeHasBeenRead(String qrToken) {

        String readStr = redis.get(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken);

        List<Object> list = new ArrayList<>();
        if (StringUtils.isNotBlank(readStr)) {
            String[] readArr = readStr.split(",");

            if (readArr.length == 2) {
                list.add(Integer.valueOf(readArr[0]));
                list.add(readArr[1]);
            }
        }

        return GraceJSONResult.ok(list);
    }


    /**
     * 手机端 点击确认登录，携带preToken与后端进行判断，如果校验成功则登录
     * 注：如果使用websocket或netty，可以在此直接通信h5
     */
    @PostMapping("goQRLogin")
    public GraceJSONResult goQRLogin(String userId, String qrToken, String preToken) {

        String preTokenRedis = redis.get(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken);

        if (StringUtils.isNotBlank(preTokenRedis)) {
            String preTokenRedisArr = preTokenRedis.split(",")[1];
            if (preTokenRedisArr.equalsIgnoreCase(preToken)) {
                // 根据用户id获得用户信息
                Users hrUser = usersService.getById(userId);
                if (hrUser == null) {
                    return GraceJSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
                }

                // 存入用户信息到redis中
                // 因为h5在未登录的状态下拿不到用户id，所以暂存用户信息到redis，如果使用websocket是可以直接通信h5获得用户id
                redis.set(REDIS_SAAS_USER_INFO + ":temp" + preToken, new Gson().toJson(hrUser), 5 * 60);

            }
        }

        return GraceJSONResult.ok();
    }


    /**
     * 企业后台确认登录
     */
    @PostMapping("checkLogin")
    public GraceJSONResult checkLogin(String preToken) {

        if (StringUtils.isBlank(preToken)) {
            return GraceJSONResult.error();
        }

        String userJson = redis.get(REDIS_SAAS_USER_INFO + ":temp" + preToken);

        if (!StringUtils.isNotBlank(userJson)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
        }

        // 确认执行登录后，生成saas用户的token，并且长期有效
        String saasUserToken = jwtUtils.createToken(userJson, TOKEN_SAAS_PREFIX);

        // 存入用户信息，长期有效
        redis.set(REDIS_SAAS_USER_INFO + ":" + saasUserToken, userJson, 5 * 60);

        return GraceJSONResult.ok(saasUserToken);
    }

    @GetMapping("info")
    public GraceJSONResult info(String token) {

        String userJson = redis.get(REDIS_SAAS_USER_INFO + ":" + token);
        Users saasUser = new Gson().fromJson(userJson, Users.class);

        SaasUserVO saasUserVO = new SaasUserVO();
        BeanUtils.copyProperties(saasUser, saasUserVO);

        return GraceJSONResult.ok(saasUserVO);
    }

    @PostMapping("logout")
    public GraceJSONResult logout(String token) {

        return GraceJSONResult.ok();
    }


}
